﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace XmlVisualizer.DiagramDesigner {

	/// <summary>
	/// Selection rectangle.
	/// </summary>
	public class RubberbandAdorner : Adorner {
		#region Member fields
		private Point? startPoint;
		private Point? endPoint;
		private Pen rubberbandPen;
		private DesignerCanvas designerCanvas;
		#endregion

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the RubberbandAdorner class.
		/// </summary>
		/// <param name="designerCanvas">DesignerCanvas to set.</param>
		/// <param name="dragStartPoint">Dragging start point.</param>
		public RubberbandAdorner(DesignerCanvas designerCanvas, Point? dragStartPoint)
			: base(designerCanvas) {
			if (designerCanvas == null)
				throw new ArgumentNullException("designerCanvas");

			this.designerCanvas = designerCanvas;
			this.startPoint = dragStartPoint;
			rubberbandPen = new Pen(Brushes.LightSlateGray, 1);
			rubberbandPen.DashStyle = new DashStyle(new double[] { 2 }, 1);
		}
		#endregion	

		#region Event handlers
		/// <summary>
		/// Invoked on mouse move.
		/// </summary>
		/// <param name="e">The event data.</param>
		protected override void OnMouseMove(System.Windows.Input.MouseEventArgs e) {
			if (e.LeftButton == MouseButtonState.Pressed) {
				if (!this.IsMouseCaptured)
					this.CaptureMouse();

				endPoint = e.GetPosition(this);
				UpdateSelection();
				this.InvalidateVisual();
			} else {
				if (this.IsMouseCaptured)
					this.ReleaseMouseCapture();
			}

			e.Handled = true;
		}

		/// <summary>
		/// Invoked on mouse up.
		/// </summary>
		/// <param name="e">The event data.</param>
		protected override void OnMouseUp(System.Windows.Input.MouseButtonEventArgs e) {
			// release mouse capture
			if (this.IsMouseCaptured)
				this.ReleaseMouseCapture();

			// remove this adorner from adorner layer
			AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.designerCanvas);
			if (adornerLayer != null)
				adornerLayer.Remove(this);

			//e.Handled = true;
		}

		/// <summary>
		/// Invoked on render.
		/// </summary>
		/// <param name="dc">The drawing instructions for a specific element. This context is provided to the layout system.</param>
		protected override void OnRender(DrawingContext dc) {
			base.OnRender(dc);

			// without a background the OnMouseMove event would not be fired!
			// Alternative: implement a Canvas as a child of this adorner, like
			// the ConnectionAdorner does.
			dc.DrawRectangle(Brushes.Transparent, null, new Rect(RenderSize));

			if (this.startPoint.HasValue && this.endPoint.HasValue)
				dc.DrawRectangle(Brushes.Transparent, rubberbandPen, new Rect(this.startPoint.Value, this.endPoint.Value));
		}
		#endregion

		#region Methods
		/// <summary>
		/// Updates the selection.
		/// </summary>
		private void UpdateSelection() {
			designerCanvas.selectionService.ClearSelection();

			Rect rubberBand = new Rect(startPoint.Value, endPoint.Value);
			foreach (Control item in designerCanvas.Children) {
				Rect itemRect = VisualTreeHelper.GetDescendantBounds(item);
				Rect itemBounds = item.TransformToAncestor(designerCanvas).TransformBounds(itemRect);

				if (rubberBand.Contains(itemBounds)) {
					if (item is Connection)
						designerCanvas.selectionService.AddToSelection(item as ISelectable);
					else {
						DesignerItem di = item as DesignerItem;
						if (di.ParentID == Guid.Empty)
							designerCanvas.selectionService.AddToSelection(di);
					}
				}
			}
		}
		#endregion
	}
}
